//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public License
// along with this program.  If not, see http://www.gnu.org/licenses/.
// 

#include "Protocol.h"

#include <cstdlib>
#include <cXMLElement.h>

#include "message_m.h"
#include "message_k.h"
#include "info.h"
#include "host_manager.h"

Define_Module(Protocol);

void Protocol::initialize()
{
	numHosts = par("protocolNumHosts");
	cntRespondedHosts = 0;
	tmpNumHosts = numHosts;
	channelRequestListTop = 0;
	// TODO - Initialize HostManager
	cXMLElement *xmlDoc = par("hostInfoXML").xmlValue();
	HostManager::getInstance()->InitializeHostInfo(xmlDoc);
	delete xmlDoc;
}

void Protocol::handleMessage(cMessage *msg)
{
	EV << msg->getArrivalGate()->getName() << endl;
	switch(msg->getKind())
	{
	case RequestChannelInfoMsgKind:
		{
			cntRespondedHosts++;
			RequestChannelInfoMsg *rscMsg = check_and_cast<RequestChannelInfoMsg *>(msg);
			if(rscMsg->getNeedSend())
			{
				channelRequestList[channelRequestListTop++] = rscMsg;
			}
		}
	break;
	case DeleteHostMsgKind:
		{
			tmpNumHosts--;
			cntRespondedHosts++;
		}
	break;
	}

	if(msg->getKind() == RequestChannelInfoMsgKind || msg->getKind() == DeleteHostMsgKind)
	{
		if(cntRespondedHosts == numHosts)
		{
			// send to sending host about their assigned channels

			ChannelInfo channelInfoList[MAX_NUM_HOST];
			getChannel(channelRequestList, channelRequestListTop, channelInfoList);

			for(int i = 0; i < channelRequestListTop; i++)
			{
				ChannelInfoMsg *caMsg = new ChannelInfoMsg(NULL, ChannelInfoMsgKind);
				caMsg->setChannelInfo(channelInfoList[i]);
				caMsg->setSenderId(channelRequestList[i]->getSenderId());
				caMsg->setReceiverId(channelRequestList[i]->getReceiverId());
				send(caMsg, "hostControlPorts$o", channelRequestList[i]->getSenderId());
			}

			channelRequestListTop = 0;
			numHosts = tmpNumHosts;
			cntRespondedHosts = 0;
			tmpNumHosts = numHosts;
		}
	}
}

// Get Host Info from HostMananger::getInstance()->getHostInfo(hostID)
void Protocol::getChannel(RequestChannelInfoMsg* requestList[], int channelRequestListTop, ChannelInfo channelInfoList[])
{
	// A basic channel assignment strategy
	for(int i = 0; i < channelRequestListTop; i++)
	{
		channelInfoList[i].init();
		channelInfoList[i].addChannel(900 + 20 * i, 900 + 20 * i + 19);
	}
}
